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.
Overview of the authorization code flow (3-legged OAuth)
Use this flow to authorize your app to act on behalf of other Indeed user accounts and those user accounts' associated employers. To use this flow, complete these steps:
Once |
1. |
Register your app to get a client ID and secret. During registration, you select the authorization code grant type, which indicates that you receive an authorization code after the user authorizes your app through the OAuth consent screen. |
For each user |
2. |
To get this code, call the |
3. |
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. |
|
For each API call |
4. |
Pass the access token each time that you call an Indeed API. |
Step 1. Get a client ID and secret
-
Go to Manage app credentials, 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.
📘 Note: Add these suffixes to these versions of your app:
-
Test:
-dev
-
Production:
-prod
For example,
AceRecruitersApp-dev
andAceRecruitersApp-prod
. -
Test:
-
Indicate whether the app is a public client, select the authorization code grant type, add 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 your company name, homepage, support email address and link to your public privacy policy, 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:
Store your client ID and secret securely. Other than including these credentials in API calls, never share your credentials or store them in a public Git repository.
Step 2. Get an authorization code
-
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 on the OAuth consent screen, 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
-
Make a
POST
request to thehttps://apis.indeed.com/oauth/v2/tokens
endpoint: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
In the request, include the:
-
Content-Type
andAccept
request headers. -
code
,client_id
,client_secret
,redirect_uri
, and thegrant_type=authorization_code
parameters.
📘 Note:
When you get an access token, you can use the basic authentication scheme instead of passing a client ID and secret in the
/oauth/v2/tokens
request body. To use this scheme, you encode and pass these credentials in anAuthorization Basic
header.The JSON response includes the response fields for
oauth/v2/tokens
:{ "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.
Step 4. Call an Indeed API
Prefix the string Bearer
to the access token value, and pass the concatenated string in an Authorization
header with each API call.
Additional tasks
Refresh an access token
Use a refresh token to refresh your access token.
Indeed returns a refresh token with the access token when your app requests and is granted the offline_access
scope.
Access tokens are valid for one hour (3600 seconds). 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.
Note:
The access token is valid for only one hour. Refresh this token after that.
Associate user account with employer account
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, use either the Indeed employer selection screen or your own employer selection screen.
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, use the prompt=select_employer
parameter.
When you specify this parameter, your OAuth app must also request scope=employer_access
. Otherwise, the Indeed employer selection screen does not appear.
For example, this link includes both the prompt=select_employer
parameter and a request for the employer_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. |
The Indeed employer selection screen lists the employers associated with the user account:
- US Robotics and Mechanical Men
- Umbrella Corporation
If the user selects one of the employers and submits the page, 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 that represents an employer ID. Use this ID when your request an access token to associate the access token with an employer, like this:
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
When you use a refresh token to get an access token, you can also use the employer
parameter. 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.
Show a custom employer selection screen
Indeed recommends that you use the standard Indeed employer selection screen to enable users to select a particular employer. To customize the employer selection screen, then you also have the option of getting employers and creating an employer selection screen.
Follow these steps:
-
Get credentials. Get an access token to trigger the OAuth consent screen, and get an access token with the
employer_access
andoffline_access
scopes.The query returns an access token, ID token, and refresh token.
-
To list employers for the current user, decode the ID token. See Get user info.
-
Create a custom employer selection screen. You can build a user interface that enables the user to select an employer.
-
Get an access token that represents an employer.
To get an access token that represents the employer, 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
Note:
In the request:
- The
grant_type
parameter has therefresh_token
value. - The
refresh_token
parameter contains the refresh token. - The
employer
parameter has the Dharma Initiative employer ID value.
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.
- The
Get user info
When using authorization code flow (3-legged OAuth), to get information about the user that registered the app, you can use an ID token or the userinfo endpoint.
ID token
The OpenID Connect specification describes an ID token. Indeed always returns an ID token with the access token. The ID token contains information about the current user. See v2/api/userinfo response fields.
To include the email
and email_verified
fields in the ID token, an app must request and get the email
scope.
When you use the authorization code flow (3-legged OAuth) to request an access token, you get an ID token automatically.
A resource server, which is an Indeed API, reads an access token, while a third-party app reads an ID token.
For example:
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
See HTTP request headers.
The response is:
{
"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, copy it into the form at https://jwt.io.
When the user grants your app both the email
and employer_access
scopes, the following response appears:
{
"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]"
}
If a user does not grant these scopes, only the sub
field is returned.
The ID token is a Base64-encoded JSON Web Token (JWT). 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
To verify that the ID token is valid, copy the key into the form at https://jwt.io.
The userinfo endpoint
To call the userinfo
endpoint, you must get the access token by using the authorization code grant type.
This curl command shows how to call the userinfo
endpoint, with a shortened token for readability:
curl -H 'Authorization:Bearer eyJraWQiOiI1OTdjYTgxNC03YTA2LTR0zh0Elm9A' \
https://secure.indeed.com/v2/api/userinfo
The information that userinfo
endpoint returns depends on the scopes that a user grants to your OAuth app. If the user does not grant your app any scopes, you receive the sub
field, which represents a user's account ID:
{
"sub": "d2d1962c0664d970"
}
If the user grants your app the email
scope, you receive the email
and email_verified
fields:
{
"sub": "a95064930d19bbc7",
"email": "swalther[email protected]",
"email_verified": true
}
Finally, if the user grants your app the employer_access
scope, you receive 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"
}
]
}
You can call the userinfo
endpoint to request account information for the current user. This endpoint returns exactly the same information as the ID token. Like the ID token, you must request and receive the email scope to get the email
and email_verified
fields.
A use case for this resource is creation of Log in with Indeed buttons. See Log in with Indeed.
The URL path is:
GET/POST https://secure.indeed.com/v2/api/userinfo
This endpoint does not have any request body parameters.
In the request, pass the access token in an Authorization 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 v2/api/userinfo response fields.
Get and manage scopes
When you request an access token, you request scopes that define your app's permissions.
Indeed authorization scopes
For a list of Indeed-supported scopes, see scopes.
When using the authorization code flow (3-legged OAuth), the authorizing user grants scopes to your app. They can grant no scopes, specific scopes, or all scopes to your app.
To determine which scopes your app has, read the scope
field in a tokens
response:
{
"access_token": "eyJraWQiOiI1OTdjYTgxNC03YTA2LTRkZTMtO",
"refresh_token": "ZenoK4KeQsg",
"id_token": "eyJraWQiOiI1OTdjYTgxNC03YTA2LTE69SSJkjQQ",
"scope": "offline_access employer_access email",
"consented_scope": "offline_access employer_access email",
"convid": "1er835qvtu54n800",
"token_type": "Bearer",
"expires_in": 3600
}
Use incremental authorization
Incremental authorization enables apps to request only the scopes that they need. Incremental authorization requires the offline_access
, which maintains the permissions that your app has. For example, if your app requests the email
scope, your app must also request the offline_access
scope.
After a user grants your app a scope, they do not need to grant the scope again.
For example, if the user requests functionality from your app that requires the employer_access
scope, the OAuth consent screen prompts the user to grant only the employer_access
scope and not the email
and offline_access
scopes.
The Current permissions tab on the OAuth consent screen lists the app's scopes.
Revoke OAuth scopes
When using the authorization code flow (3-legged OAuth), a user can use the Authorized Applications page to revoke scopes from an app.
Note:
You cannot revoke scopes individually. You can revoke all scopes and, when using the app, grant scopes again.
See also
- OAuth glossary for common OAuth term descriptions
- Error Response in the RFC6749: IETF OAuth 2.0 Authorization Framework for a description of the error response
- userinfo endpoint for an example of an API call
- OAuth reference for request headers, request body parameters, response fields, Indeed-supported scopes, and the basic authentication scheme
- Log in with Indeed button for Indeed-provided images to create Log In with Indeed buttons
- Upgrade OAuth to upgrade your OAuth integration to the Indeed OAuth endpoint v2
Updated 3 days ago