Authorization code flow (3-legged OAuth)
Authenticate your app to act on behalf of other Indeed user accounts and the users' associated employers.
Note:
By using this API and its documentation and building an integration, you agree to the Additional API Terms and Guidelines.
Authorization code flow (3-legged OAuth) overview
Note:
For an overview of Indeed authentication, see Indeed authentication.
Authorize your app to act on behalf of other Indeed user accounts and those user accounts' associated employer accounts.
To use this flow, complete these steps:
Once |
|
|
For each app |
|
|
|
||
|
||
For each API call |
|
See also Additional tasks.
Step 1. Register your app
Register your app to get a client ID and secret, which identify your app.
-
On the Manage app credentials page, sign in to your Indeed account, then click Register new application.
-
Enter your app name and description, select the OAuth 2.0 credential type, then click Save and continue.
📘 Notes:
-
Register both test and production versions of an app to generate separate API credentials. During registration, add these suffixes to their names:
-
-dev
to test apps. For example,AceRecruitersApp-dev
. -
-prod
to production apps. For example,AceRecruitersApp-prod
.
-
-
The Indeed Apply credential type is for Indeed Apply integrations only.
-
-
For the OAuth 2.0 credential type:
Field Value Public client Indicate whether the app is a public client.
Allowed grant types Select the authorization code grant type.
Redirect URL Define one or more redirect URLs.
Then, click Save and continue.
-
Indicate whether you want your app to be reviewed, then click Save and continue.
-
Optionally, provide additional company information, then click Save and continue.
-
Preview your app information, then click Complete registration.
The page shows information about your app, including the client ID, and if your app is not a public client, your client secret.
📘 Important:
Secure these credentials. Never share them or store them in a public Git repository.
Step 2. Get an authorization code
To get an authorization code, call the oauth/v2/authorize
endpoint with your client ID. In response to this call, Indeed shows the OAuth consent screen to the user, the user authorizes your app, then Indeed passes an authorization code to the redirect URL that you specified during app registration.
-
To add an Indeed authorization link to your app, call the
https://secure.indeed.com/oauth/v2/authorize
endpoint with request body parameters:https://secure.indeed.com/oauth/v2/authorize?client_id=6nwwcdklwgktryjw2j5fxh5t2fyneule7zg7mvw3pf9jbx3wmewzlxkdz1jxvs6b&redirect_uri=http%3A%2F%2Fwww.acerecruitersllc.com%2Foauth%2Findeed&response_type=code&state=employer1234&scope=email+offline_access+employer_access
The call shows the OAuth consent screen to the user. If the user clicks Allow, Indeed redirects them to your app at the
redirect_uri
, with thecode
andstate
response fields appended. -
Capture the
code
parameter from theredirect_uri
page:GET http://www.acerecruitersllc.com/oauth/indeed?code=rXZSMNyYQHQ&state=employer1234
Step 3. Get an access token
To make API calls, you must include an access token in each call. The token identifies an Indeed account and proves that your app is authorized to make calls on behalf of this account.
To get an access token, you exchange your client ID and secret and either an authorization code or, if the access token expires, a refresh token, for one.
-
Make a
POST
request to thehttps://apis.indeed.com/oauth/v2/tokens
endpoint.In the request, include:
Content-Type
andAccept
request headers.code
,client_id
,client_secret
,redirect_uri
, and thegrant_type=authorization_code
parameters.
For example:
curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: application/json' \\ -d 'code=rXZSMNyYQHQ' \\ -d 'client\_id=6nwwcdklwgktryjw2j5fxh5t2fyneule7zg7mvw3pf9jbx3wmewzlxkdz1jxvs6b' \\ -d 'client\_secret=02KKpg6yLXw2v3FKf5lqyFGtMQCvPBNbJIw89SoSd9fts1LAdlvwUQQ6dwhAhEXv' \\ -d 'redirect\_uri=http://localhost:3000/oauth/callback' \\ -d 'grant\_type=authorization\_code' \\ https://apis.indeed.com/oauth/v2/tokens
The JSON response shows the following response fields:
{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV[...]", "id_token": "eyJraWQiOiJlMzEzZTc4My1lM2YwLTQ3ZWMtY[...]", "refresh_token": "rXZSMNyYQHQ", "expires_in": 3600, "token_type": "Bearer", "scope": "email offline_access", "consented_scope": "email offline_access" }
The JSON response for an error includes these fields:
{ "error": "invalid_request", "error_description": "Invalid authentication request." }
-
Securely store the access token and refresh token.
Note:
When you get an access token, you can use the basic authentication scheme instead of passing your client ID and secret in the
/oauth/v2/tokens
request body.
Step 4. Refresh your access token
Use a refresh token to refresh your access token.
Indeed returns a refresh token with the access token when your app gets the offline_access
scope.
Access tokens are valid for one hour. Refresh tokens are valid for 60 days from when they are issued. With each refresh, the refresh token's expiration date is extended to 60 days from the most recent refresh.
To refresh your access token:
-
Make a
POST
request to thehttps://apis.indeed.com/oauth/v2/tokens
endpoint.In the call, include the
Content-Type
andAccept
request headers and therefresh_token
,client_id
,client_secret
, and thegrant_type=refresh_token
request body parameters.curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: application/json' \ -d 'refresh_token=8qE_nKXUng4' \ -d 'client_id=6nwwcdklwgktryjw2j5fxh5t2fyneule7zg7mvw3pf9jbx3wmewzlxkdz1jxvs6b' \ -d 'client_secret=02KKpg6yLXw2v3FKf5lqyFGtMQCvPBNbJIw89SoSd9fts1LAdlvwUQQ6dwhAhEXv' \ -d 'grant_type=refresh_token' \ https://apis.indeed.com/oauth/v2/tokens
The JSON response includes these fields:
{ "access_token": "eyJhbGciOiJIUzI1NiIslKxwRJSMeKKeJf36POk6yJV_adQs[...]", "id_token": "eyJraWQiOiJlMzEzZTc4My1lM2YwLTQ3ZWMtYmJlMi1jMWRlNGYy[...]", "refresh_token": "rXZSMNyYQHQ", "convid": "1c1a1s8540kkt89p", "scope": "email offline_access", "token_type": "Bearer", "expires_in": 3600 }
If an error occurs, the JSON response includes these fields:
{ "error": "invalid_request", "error_description": "Invalid authentication request." }
-
Pass your access token in each API request.
Step 5. Call an Indeed API
In each API call, pass the access token in the Authorization
header with the Bearer
authentication scheme.
For example:
Authorization: Bearer <token>
Additional tasks
Enable user to select an employer
You can associate an Indeed user account with one or more employer accounts. When you call an Indeed API, the API might require you to represent a particular employer. To associate an employer with an access token, show the user either the Indeed-hosted employer selection screen or your own employer selection screen to enable the user to select an employer from a list of employers associated with the user.
Note:
An access token can represent only one employer at a time. To switch employers, generate an access token. For example, use a refresh token to generate an access token.
Show the Indeed employer selection screen
-
To request the creation of an authorization link to display the Indeed employer selection screen, specify the
prompt=select_employer
andscope=employer_access
request body parameters. Otherwise, the Indeed employer selection screen does not appear.For example, this link includes both the
prompt=select_employer
parameter and a request for theemployer_access
scope:https://secure.indeed.com/oauth/v2/authorize?client_id=bf7622efee705862320df0f5c7690b22f60ba24f236aaf4adf5b7a36fa0adcf1&redirect_uri=https%3A%2F%2Fexample.com%2Foauth&response_type=code&state=random&scope=email+offline_access+employer_access&prompt=select_employer
This authorization link triggers these screens to appear:
Screen Description Authentication Appears when the user is logged out of Indeed. OAuth consent Enables a user to grant consent for any scopes that the OAuth app requests, such as the employer_access
scope.Indeed employer selection Enables a user to select an employer from a list of employers associated with the user account. -
If the user selects an employer, a redirect URI parameter transmits the employer ID to your OAuth app:
https://example.com/oauth/callback?state=random&employer=6d2f02224e30d401810b1726eb246d8d&code=e_IEr5UlBys
The URL includes an
employer
parameter, which contains an employer ID value, and associates the access token with that employer:curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: application/json' \ -d 'code=e_IEr5UlBys' \ -d 'client_id=bf7622efee705862320df0f5c7690b22f60ba24f236aaf4adf5b7a36fa0adcf1' \ -d 'client_secret=02KKpg6yLXw2v3FKf5lqyFGtMQCvPBNbJIw89SoSd9fts1LAdlvwUQQ6dwhAhEXv' \ -d 'redirect_uri=https://example.com/oauth' \ -d 'grant_type=authorization_code' \ -d 'employer=6d2f02224e30d401810b1726eb246d8d' \ https://apis.indeed.com/oauth/v2/tokens
Notes:
- You can also use the
employer
parameter when you exchange a refresh token for an access token. - If the user does not select an employer or the user account has no associated employers, then the redirect URI does not include an
employer
parameter.
Warning:
Don't assume that the redirect URI includes an
employer
parameter even when you use theprompt=select_employer
parameter. - You can also use the
Show a custom employer selection screen
Although Indeed recommends that you enable users to select an employer from the standard Indeed employer selection screen, you can also create a custom employer selection screen:
-
Get an access token to trigger the OAuth consent screen. When you get the token, request the
employer_access
andoffline_access
scopes.The query returns an access token, ID token, and refresh token.
-
To list employers for the current user, use the JSON Web Tokens Debugger to decode the ID token.
-
Build a custom employer selection screen that enables the user to select an employer.
-
To get an access token that represents the employer that the user selected, pass the employer ID in the
employer
parameter of theoauth/v2/tokens
endpoint.curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: application/json' \ -d 'refresh_token=4U0xku8M9u0' \ -d 'client_id=b0c3b1092225d3e99f85d7aa3fe1e6001f9a0bb798717cbc2008e58fbda3ef16' \ -d 'client_secret=2YFoyZOWmr83njlsIuyCL9QQq5jZkRCR4UtmHGp22MRzjIhe5RbynnAGmuYLFbYx' \ -d 'grant_type=refresh_token' \ -d 'employer=13ef9940a7c1f0500a7e411e74178c4e' \ https://apis.indeed.com/oauth/v2/tokens
In this request:
Parameter Contains grant_type
refresh_token
refresh_token
The refresh token employer
An employer ID When you use a refresh token to get an access token, an OAuth consent screen is not necessary.
Use this access token for API calls on behalf of the consenting user and only for this employer.
Get user information
To get information about the user account that registers an app, use either the:
ID token
An ID token is a Base64-encoded JSON Web Token (JWT) that you get automatically when you get an access token. This token proves that the user has been authenticated.
Note:
An Indeed API reads an access token while a third-party app reads an ID token to verify the user's identity.
The ID token contains information about the current user. See Response fields for v2/api/userinfo.
Because the JSON Web Token is signed, use the public key to verify that the token is valid:
https://secure.indeed.com/.well-known/keys
For information about ID tokens, see ID Token in the OpenID Connect Core 1.0 incorporating errata set 1 specification.
-
So that the ID token includes the
email
andemail_verified
fields, your app must get theemail
scope. -
Request an access token:
curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: application/json' \ -d 'code=qCwk_cdC4Ms' \ -d 'client_id=a0c3b1092225d3e99f85d7aa3fe1e6001f9a0bb798717cbc2008e58fbda3ef16' \ -d 'client_secret=1YFoyZOWmr83njlsIuyCL9QQq5jZkRCR4UtmHGp22MRzjIhe5RbynnAGmuYLFbYx' \ -d 'redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Foauth%2Fcallback' \ -d 'grant_type=authorization_code' \ https://apis.indeed.com/oauth/v2/tokens
The JSON response shows the
oauth/v2/tokens
response fields:{ "access_token": "eyJraWQiOiINiYzIwMDh9hrYboL9BMnU_Pfbv41Nqj3nUuMbprUtRgQ", "convid": "1erq23om7t5bu800", "scope": "email employer_access", "id_token": "eyJraWQiMWQ4NTciLCJ0eXAiOiJKV1LmNvbSzNjMwfQ.Jrb1fX-aPtkV9nQK9U1LFP0V61eEApo3pFFPaGjT9zA", "token_type": "Bearer", "expires_in": 3600 }
-
To decode the ID token value, copy it into the JSON Web Tokens Debugger.
-
If the user does not grant your app any scopes, the response shows the
sub
field, which represents a user's account ID:{ "sub": "d2d1962c0664d970" }
-
If the user grants your app the
email
andemployer_access
scopes, the response shows theemail
andemail_verified
fields:{ "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": "[email protected]" }
-
The userinfo endpoint
To get account information for the current user, call the v2/api/userinfo
endpoint, which returns the same information the ID token returns.
For example, you need to get account information when you create Log in with Indeed buttons.
The URL path is:
GET/POST https://secure.indeed.com/v2/api/userinfo
This endpoint does not have any request body parameters.
In this request, pass the access token in the Authentication
header with the Bearer
authentication scheme.
Authorization: Bearer <token>
where <token>
is the your access token.
For example:
GET /v2/api/userinfo HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Host: secure.indeed.com
A successful request returns the HTTP status code 200
and a response payload:
HTTP/1.1 200 OK
Content-Type: application/json
{
"sub": "248289761001",
"email": "min[email protected]",
"email_verified": true
}
See Response fields for v2/api/userinfo.
To call the v2/api/userinfo
endpoint:
-
Request the
email
scope to return theemail
andemail_verified
fields. -
Get an access token with the authorization code grant type.
-
Call the
userinfo
endpoint.This curl command shows how to call the endpoint, with a shortened token for readability:
curl -H 'Authorization:Bearer eyJraWQiOiI1OTdjYTgxNC03YTA2LTR0zh0Elm9A' \ https://secure.indeed.com/v2/api/userinfo
The
userinfo
endpoint returns information for the scopes that a user grants to your OAuth app:-
If the user does not grant your app any scopes, the response shows the
sub
field, which represents a user's account ID:{ "sub": "d2d1962c0664d970" }
-
If the user grants your app the
email
scope, the response shows theemail
andemail_verified
fields:{ "sub": "a95064930d19bbc7", "email": "swalther[email protected]", "email_verified": true }
-
If the user grants your app the
employer_access
scope, the response shows a list of employers, or advertisers, for the user account:{ "sub": "bc8c847009a955c9", "email": "[email protected]", "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 flow (3-legged OAuth), Indeed limits the number of redirect URLs to five, which conforms to the security best practices for OAuth apps.
To dynamically redirect a user to multiple URLs:
-
Add a
state
parameter 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
-
After the Indeed user completes the authorization code flow (3-legged OAuth), Indeed returns the
state
query parameter value in your redirect URL:GET http://www.acerecruitersllc.com/oauth/indeed?code=rXZSMNyYQHQ&state=AnyValue
-
To pass a URL with the
state
parameter, 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
state
parameter value to redirect them to another destination, such ashttps://somesite.com
.
Guidelines
Do not expose the authorization code
Note:
If you redirect a user to an untrusted website, you inadvertedly reveal the OAuth authorization code in the HTTP
Referer
header, which contains the URL that requested a page.The HTTP referer specification misspells referer.
You might unintentionally expose the authorization code to the website that the state
parameter represents. That website likely logs the authorization code in its website logs.
To prevent the authorization code from leaking:
- 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 and not any URLs requested before that.
Do not append query parameters to the redirect URI
Currently, Indeed supports query parameters in the redirect URI.
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.com
The authorize
URL includes a redirect_uri
parameter with the https://somesite.com?return=https://someothersite.com
value.
Note:
- The
redirect_uri
parameter includes thereturn
query parameter, which contains another redirect URL.- Indeed encourages you to use the
state
parameter rather than using query parameters in theredirect_uri
parameter because Indeed might discontinue that support of query parameters in theredirect_uri
parameter.
See also
Topic | Description |
---|---|
OAuth glossary | Get descriptions for common OAuth terms. |
OAuth reference | Specify HTTP request headers and parameters and review response fields in the client credentials flow (2-legged OAuth) and the authorization code flow (3-legged OAuth). |
Scopes | Indeed authorization scopes. |
Error Response in RFC6749: The OAuth 2.0 Authorization Framework | The error response. |
Log in with Indeed | Indeed images to create Log In with Indeed buttons. |
Upgrade OAuth | How to upgrade your OAuth integration to the Indeed OAuth v2 endpoint |
Updated 4 days ago