- Authorization code grant type (3-legged OAuth) overview
- Become an Indeed partner
- Get an authorization code
- Get your OAuth credentials
- Get a 3-legged access token
- Refresh your 3-legged access token
- Call Indeed APIs
- Get an access token that represents an employer
- Show the Indeed employer selection screen
- Show a custom employer selection screen
- Get employer access token
- Get user information
- ID token
- The userinfo endpoint
- Dynamically redirect a user to multiple URLs
- Guidelines
- Prevent the authorization code from leaking
- Do not append query parameters to the redirect URI
- See also
Authorization code grant type (3-legged OAuth)
Authorize your app to act on behalf of Indeed user accounts and associated employer accounts.
By using this API and its documentation and building an integration, you agree to the Additional API Terms and Guidelines.
Authorization code grant type (3-legged OAuth) overview
Use the authorization code grant type (3-legged OAuth) to let your app act on behalf of Indeed user accounts and their associated employer accounts.
When you become an Indeed partner, Indeed sets up an app for your integration. Sign in to Partner Console to view your app and OAuth credentials (client ID, secret, and authorization code for 3-legged OAuth). Exchange credentials for an access token to authenticate API calls.
You can also:
- Get an access token that represents an employer.
- Get information about the user account that registered an app.
- Redirect a user to multiple URLs dynamically.
- Prevent the authorization code from leaking.
Become an Indeed partner
If you are not yet a partner, become an Indeed partner.
Get an authorization code
Your app must request a 3-legged OAuth credential: an authorization code.
To start the authorization code flow, build a request URL to Indeed's OAuth 2.0 server that requests the email, offline_access, and employer_access permissions from the user.
Redirect the user to that URL. Indeed shows the OAuth consent screen.
If the user selects Allow, Indeed sends an authorization code to your redirect_uri endpoint and appends the code and state response fields. The authorization code expires in 10 minutes.
-
Build the request URL for the Indeed OAuth 2.0 server at
https://secure.indeed.com/oauth/v2/authorize.This example URL requests the
email,offline_access, andemployer_accesspermissions from the user.The example includes line breaks and spaces for readability:
https://secure.indeed.com/oauth/v2/authorize?client_id=c4acac1b35917a14c11947f6564ee28a0758398cd0fdf4deec685c40f14bb8a8&redirect_uri=http%3A%2F%2Fwww.acerecruitersllc.com%2Foauth%2Findeed&response_type=code&scope=email+offline_access+employer_access&state=employer1234The query parameters for
oauth/v2/authorizeare:oauth/v2/authorize query parameters Query parameter Required Description client_id✔
Your client ID.
redirect_uri✔
URL-encoded redirect URL. Identifies the page on your site where you capture the authorization code. It must match a redirect URL that you registered for your app.
response_type✔
Always
code.scope✔
Permissions that your app requests. URL-encode and space-delimit scopes; URL-encoding replaces the spaces with plus signs (
+).This example requests the
email,offline_access, andemployer_accesspermissions from the user.stateRecommended
Prevents CSRF attacks. Use any unique string that your app generates to maintain state between the request and callback. Indeed returns this value to your redirect URI.
-
Redirect the user to the request URL.
Indeed shows the OAuth consent screen to the user who owns the account that you want to access.
If the user selects Allow, Indeed sends an authorization code to your
redirect_uriand appends thecodeandstateresponse fields. -
Capture the
codeparameter from theredirect_uripage.For example:
GET http://www.acerecruitersllc.com/oauth/indeed?code=rXZSMNyYQHQ&state=employer1234
Get your OAuth credentials
-
Sign in to Partner Console with your Indeed user account.
-
On the Dashboard, select your app in the Apps list.
The Credentials tab on the app details page shows your OAuth credentials: a client ID and a client secret.
Get a 3-legged access token
Access tokens last one hour. To refresh an access token, see Refresh your 3-legged access token.
To get an access token, send a POST request to https://apis.indeed.com/oauth/v2/tokens with Accept and Content-Type request headers and the request body parameters.
curl -L -X POST 'https://apis.indeed.com/oauth/v2/tokens' \ -H 'Accept: application/json' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=authorization_code' \ -d 'client_id=<client_id>' \ -d 'client_secret=<client_secret>' \ -d 'code=<authorization_code>' \ -d 'code_verifier=<code_verifier>' \ -d 'redirect_uri=http://www.acerecruitersllc.com/oauth/indeed'The request headers are:
The request body parameters for oauth/v2/tokens are:
| Request body parameter | Required | Value |
|---|---|---|
grant_type | ✔ | authorization_code |
client_id | ✔ | Your client ID. |
client_secret | ✔ | Your client secret. |
scope | Conditional | Scopes that grant your app permissions. |
code | ✔ | Your authorization code. |
code_verifier | ✔ when you use PKCE | The code verifier that generates the code_challenge. Confidential clients should use a code_challenge. Generate the OAuth PKCE code challenge from the code verifier as defined in RFC 7636: Proof Key for Code Exchange by OAuth Public Clients. |
redirect_uri | ✔ | Your URL-encoded redirect URL. Must match the redirect URL that you used to get the authorization code. |
{ "access_token": "<access_token>", "convid": "1eis1tplg01fe802", "refresh_token": "<refresh_token>", "scope": "offline_access email", "token_type": "Bearer", "expires_in": 3600}Refresh your 3-legged access token
To refresh an access token, send a POST request to https://apis.indeed.com/oauth/v2/tokens with Accept and Content-Type request headers and the request body parameters:
curl -L -X POST 'https://apis.indeed.com/oauth/v2/tokens' \ -H 'Accept: application/json' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=refresh_token' \ -d 'client_id=<client_id>' \ -d 'client_secret=<client_secret>' \ -d 'refresh_token=<refresh_token>' The request headers are:
| Header | Value |
|---|---|
Accept |
|
Content-Type |
|
The request body parameters for oauth/v2/tokens are:
| Request body parameter | Required | Value |
|---|---|---|
grant_type | ✔ | refresh_token |
client_id | ✔ | Your client ID. |
client_secret | ✔ | Your client secret. |
refresh_token | ✔ | Your refresh token. |
{ "access_token": "<access_token>", "id_token": "<id_token>", "refresh_token": "<refresh_token>", "convid": "1c1a1s8540kkt89p", "scope": "email offline_access", "token_type": "Bearer", "expires_in": 3600}Call Indeed APIs
To call an Indeed GraphQL API, send a POST request to https://apis.indeed.com/graphql with these headers and your GraphQL query or mutation:
curl -L 'https://apis.indeed.com/graphql' \ -H 'Authorization: Bearer <access_token>' \ -H 'Content-Type: application/json' \ -d '{"query":"query {\n jobSearch(\n location: { radius: 5, radiusUnit: MILES, where: \"Austin\" }\n what: \"Nurse\"\n limit: 5\n ) {\n results {\n job {\n title\n sourceEmployerName\n }\n }\n }\n}","variables":{}}'Request headers:
| Header | Value | Description |
|---|---|---|
|
| Use this header to authenticate with the server and access protected resources. Pass the access token in this header with the For the See Get an access token, Authorization header, and Basic authentication scheme. |
|
| The media type of the resource. See Content-Type header. |
The -d parameter specifies the GraphQL query:
query { jobSearch(location: { radius: 5, radiusUnit: MILES, where: "Austin" } what: "Nurse" limit: 5) { results { job { title sourceEmployerName } } }}{ "errors": [{ "message": "The client does not have access to the 'job-retrieval-service' service.", "extensions": { "code": "INTERNAL_SERVER_ERROR" } }], "data": null}Get an access token that represents an employer
Some Indeed APIs require an access token that represents an employer or advertiser.
Show the user one of these screens:
On either screen, the user picks an employer from the employers associated with their account.
Then, get an access token for that employer.
Each access token represents one employer. To switch employers, get a new access token.
Show the Indeed employer selection screen
-
To get an authorization link that shows the Indeed employer selection screen, call the
https://secure.indeed.com/oauth/v2/authorizeendpoint with theprompt=select_employerandscope=employer_accessquery parameters.This call includes both the
prompt=select_employerandscope=employer_accessquery parameters:https://secure.indeed.com/oauth/v2/authorize?client_id=<client_id>&redirect_uri=https%3A%2F%2Fexample.com%2Foauth&response_type=code&state=random&scope=email+offline_access+employer_access&prompt=select_employerThis authorization link triggers the display of these screens:
Indeed-provided screens Screen Description Authentication
Appears when the user is signed out of Indeed.
OAuth consent
Enables a user to grant consent for any scopes that the OAuth app requests, such as the
employer_accessscope.Indeed employer selection
Enables a user to select an employer from a list of employers associated with the user account.
Use Partner Console to view what the OAuth consent screen looks like to your users.
-
When the user selects an employer, Indeed adds the employer ID to your redirect URI:
https://example.com/oauth/callback?state=random&employer=6d2f02224e30d401810b1726eb246d8d&code=e_IEr5UlBysThe URL includes an employer parameter that holds the employer ID.
Do not assume that the redirect URI always includes an employer parameter, even when you set prompt=select_employer.
-
Continue to Get employer access token.
Show a custom employer selection screen
Indeed recommends the standard Indeed employer selection screen. To use your own screen:
-
Get a 3-legged access token to trigger the OAuth consent screen, and request the
employer_accessandoffline_accessscopes.The response includes an access token, ID token, and refresh token.
-
Decode the ID token in the JSON Web Tokens Debugger to list the employers for the current user.
-
Build a custom screen that lets the user select an employer.
-
Continue to Get employer access token.
Get employer access token
Get an access token that represents the employer the user picked from the employer selection screen.
To get the employer access token, send a POST request to https://apis.indeed.com/oauth/v2/tokens with Accept and Content-Type request headers and the request body parameters:
curl -L -X POST 'https://apis.indeed.com/oauth/v2/tokens' \ -H 'Accept: application/json' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=authorization_code' \ -d 'client_id=<client_id>' \ -d 'client_secret=<client_secret>' \ -d 'redirect_uri=http://localhost' \ -d 'code=<authorization_code>' \ -d 'employer=<employer_id>'The request headers are:
| Header | Value |
|---|---|
Accept |
|
Content-Type |
|
The request body parameters for oauth/v2/tokens are:
| Request body parameter | Required | Value |
|---|---|---|
grant_type | ✔ |
Or:
When using a refresh token to get an access token, no OAuth consent screen is required. |
client_id | ✔ | Your client ID. |
client_secret | ✔ | Your client secret. |
code | ✔ when using an authorization code to get an access token | The authorization code. |
redirect_uri | ✔ | Your URL-encoded redirect URL. |
refresh_token | ✔ when using a refresh token to get an access token | The refresh token. |
employer | ✔ | The ID of the employer. Specify the ID of the employer that the user selected. |
The response contains an access token that represents the employer.
{ "access_token": "<access_token>", "scope": "employer_access", "token_type": "Bearer", "expires_in": 3600}If you request an access token for an employer that is not associated with the user who registered the app, Indeed returns this error:
{ "error_description": "Invalid request", "error": "invalid_request"}Use this access token to call APIs on behalf of the consenting user, and only for this employer.
You can also pass the employer parameter when you exchange a refresh token for an access token.
If the user does not pick an employer, or the user account has no associated employers, the redirect URI omits the employer parameter.
Get user information
To get information about the user account that registered an app, use either:
- The ID token
- The userinfo endpoint
ID token
An ID token is a Base64-encoded JSON Web Token (JWT) that you receive automatically when you Get an access token. The ID token proves that Indeed authenticated the user.
Indeed APIs read the access token; third-party apps read the ID token to verify the user's identity.
The ID token carries information about the current user. See id_token.
The JSON Web Token is signed. Verify it with the public key:
https://secure.indeed.com/.well-known/keysFor more about ID tokens, see ID Token in the OpenID Connect Core 1.0 incorporating errata set 1 specification.
-
To include the
emailandemail_verifiedfields in the ID token, request theemailscope. -
To get an access token, send a
POSTrequest tohttps://apis.indeed.com/oauth/v2/tokenswithAcceptandContent-Typerequest headers and the request body parameters:curl -L -X POST 'https://apis.indeed.com/oauth/v2/tokens' \-H 'Accept: application/json' \-H 'Content-Type: application/x-www-form-urlencoded' \-d 'grant_type=authorization_code' \-d 'client_id=<client_id>' \-d 'client_secret=<client_secret>' \-d 'redirect_uri=http://localhost' \-d 'code=<authorization_code>'The request headers are:
Get access token request headers Header Value Acceptapplication/jsonContent-Typeapplication/x-www-form-urlencodedThe request body parameters for
oauth/v2/tokensare:oauth/v2/tokens request body parameters Request body parameter Required Value grant_type✔ authorization_codeOr:
refresh_tokenWhen you use a refresh token to get an access token, an OAuth consent screen is not necessary.
client_id✔ Your client ID.
client_secret✔ Your client secret.
code✔ when using an authorization code to get an access token The authorization code. redirect_uri✔ Your URL-encoded redirect URL. refresh_token✔ when using a refresh token to get an access token The refresh token. employer✔ The employer ID. Specify the ID of the employer that the user selected. The JSON response shows the
id_tokenfield:{"access_token": "<access_token>","convid": "1erq23om7t5bu800","scope": "email employer_access","id_token": "<id_token>","token_type": "Bearer","expires_in": 3600} -
To decode the ID token, paste it into the JSON Web Tokens Debugger.
The decoded payload includes the
subfield, which holds the user's account ID:{"sub": "d2d1962c0664d970"}The response shows the
emailandemail_verifiedfields:{"aud": "a0c3b1092225d3e99f85d7aa3fe1e6001f9a0bb798717cbc2008e58fbda3ef16","sub": "d2d1962c0664d970","employers": [{"id": "13ef9940a7c1f0500a7e411e74178c4e","name": "Dharma Initiative"}, {"id": "6d2f02224e30d401810b1726eb246d8d","name": "Umbrella Corporation"}],"email_verified": true,"iss": "https://secure.indeed.com","exp": 1610417960,"iat": 1610414360,"email": "somebody@indeed.com"}
The userinfo endpoint
To get account information for the current user, send a GET request to https://secure.indeed.com/v2/api/userinfo with the Authorization: Bearer <access_token> header. The endpoint takes no query parameters or request body.
For example, call this endpoint to get account information when you build Log in with Indeed buttons.
The response contains the same information that the ID token returns.
A successful request returns the HTTP status code 200 and a response payload:
HTTP/1.1 200 OKContent-Type: application/json
{ "sub": "248289761001", "email": "mina.ray@myemail.world", "email_verified": true}To call the v2/api/userinfo endpoint:
-
Request the
emailscope to receive theemailandemail_verifiedfields. -
Get a 3-legged access token with the authorization code grant type.
-
Send a
GETrequest tohttps://secure.indeed.com/v2/api/userinfowith theAuthorization: Bearer <access_token>header:The response contains information for the scopes that a user grants to your OAuth app:
-
The response shows the
subfield, which is the user's account ID:{"sub": "d2d1962c0664d970"} -
The response shows the
emailandemail_verifiedfields:{"sub": "a95064930d19bbc7","email": "somebody+samples@indeed.com","email_verified": true} -
The response lists employers, or advertisers, for the user account:
{"sub": "bc8c847009a955c9","email": "somebody+employer@indeed.com","email_verified": true,"employers": [{"id": "084a39249af95beedfb90cc5d2b8833c","name": "Dharma Initiative"},{"id": "865e08b649774436ee1f410b611fad7c","name": "Umbrella Corporation"},{"id": "4bc393648e880bc94dd6cef8efbc8486","name": "US Robotics and Mechanical Men"}]}
-
Dynamically redirect a user to multiple URLs
When you register an OAuth client app that uses the authorization code grant type (3-legged OAuth), Indeed limits you to five redirect URLs to follow security best practices for OAuth apps.
To redirect a user to multiple URLs dynamically:
-
Add a
stateparameter to your authorize URL:https://secure.indeed.com/oauth/v2/authorize?client_id=6nwwcdklwgktryjw2j5fxh5t2fyneule7zg7mvw3pf9jbx3wmewzlxkdz1jxvs6b&redirect_uri=http%3A%2F%2Fwww.acerecruitersllc.com%2Foauth%2Findeed&response_type=code&scope=email+offline_access+employer_access&state=AnyValue -
Indeed returns the
statequery parameter in your redirect URL:GET http://www.acerecruitersllc.com/oauth/indeed?code=rXZSMNyYQHQ&state=AnyValue -
To pass a URL with the
stateparameter, such ashttps://somesite.com, URL-encode it:https://secure.indeed.com/oauth/v2/authorize?client_id=6nwwcdklwgktryjw2j5fxh5t2fyneule7zg7mvw3pf9jbx3wmewzlxkdz1jxvs6b&redirect_uri=http%3A%2F%2Fwww.acerecruitersllc.com%2Foauth%2Findeed&response_type=code&scope=email+offline_access+employer_access&state=https%3A%2F%2Fsomesite.com -
When Indeed redirects the user to your app, use the
stateparameter to redirect them to another destination, such ashttps://somesite.com.
Guidelines
Prevent the authorization code from leaking
If you redirect a user to an untrusted website, you expose the OAuth authorization code in the HTTP Referer header, which carries the URL of the page that made the request.
You can also expose the authorization code to the website that the state parameter points to. That website most likely records the authorization code in its logs.
To prevent leakage, redirect the user to another trusted page in your app before you redirect them to the untrusted app. The HTTP Referer header reveals only the latest URL, not earlier URLs in the chain.
Do not append query parameters to the redirect URI
Indeed currently accepts query parameters in the redirect_uri parameter.
https://secure.indeed.com/oauth/v2/authorize?client_id=80f9f4bd6a34cac31daebe1a093a606ce6b34e91ae6cfa139432ae387269a529&response_type=code&state=random&scope=email+offline_access+employer_access&redirect_uri=https%3A%2F%2Fsomesite.com%3Freturn%3Dhttps%3A%2F%2Fsomeothersite.comIn this example, the redirect_uri parameter is part of the https://secure.indeed.com/oauth/v2/authorize URL.
The redirect_uri value is https://somesite.com?return=https://someothersite.com, which embeds another redirect URL in the return query parameter.
Use the state parameter instead of query parameters in redirect_uri.
See also
- Credentials
- HTTP request headers
- oauth/v2/tokens endpoint
- v2/api/appinfo endpoint
- Basic authentication scheme
- Request body parameters for oauth/v2/tokens
- Troubleshoot OAuth errors
- Troubleshoot GraphQL errors