Authentication

Gaining OAuth 2.0 Credentials

In order to make API calls, you must first register your application (after logging in with your DeviantArt account).

During registration you will choose a client type:

  • Confidential — server-side applications that can securely store a secret. You will receive both a client_id and a client_secret.
  • Public — browser-based (SPA) or native/mobile applications that cannot protect a secret. You will receive only a client_id. Authentication relies on PKCE instead of a client secret.

You can manage your applications on the Applications page.

Relevant specifications:

OAuth 2.1 and OAuth 2.0

All newly registered applications use OAuth 2.1, which incorporates security best practices from RFC 7636 (PKCE) and the OAuth 2.0 Security Best Current Practice (RFC 9700). Existing applications continue to operate under OAuth 2.0 rules and can be upgraded to OAuth 2.1 at any time from the Applications page.

The key differences for OAuth 2.1 applications are:

  • PKCE is required for all Authorization Code flows (S256 method only).
  • The Implicit grant (response_type=token) is not available. Use Authorization Code with PKCE instead.
  • Redirect URIs must match exactly (no path-prefix matching).
  • Bearer tokens must be sent via the Authorization header or POST body — query string tokens are rejected.
  • Public clients authenticate with PKCE alone and do not require a client_secret.

OAuth2 Basics

The API supports the following grant types:

  • Authorization Code (with PKCE) — gives your app access to a user's account. This is the recommended grant type for all applications.
  • Client Credentials — gives your app access to public endpoints that do not require user authorization.

Endpoints document their required authentication method in the Authentication section of the endpoint documentation.

Authorization Code (with PKCE)

The Authorization Code grant is the standard OAuth 2 grant type and gives your app access to aspects of a user's account. For OAuth 2.1 applications, PKCE is mandatory. For legacy OAuth 2.0 applications, PKCE is optional but strongly recommended.

An overview of the authentication flow is illustrated below:

OAuth 2 Basic Authentication Flow

Client Credentials

The Client Credentials grant gives your app access to "public" endpoints and does not require user authorization. An overview of the authentication flow is illustrated below:

OAuth 2 Client Credentials Flow

Proof Key for Code Exchange (PKCE)

PKCE (RFC 7636) prevents authorization code interception attacks and is the mechanism that allows public clients to use the Authorization Code grant securely without a client secret.

The PKCE flow works as follows:

  1. Your application generates a random string called the code_verifier (43–128 characters, using [A-Z] / [a-z] / [0-9] / - . _ ~).
  2. Compute the code_challenge as BASE64URL(SHA256(code_verifier)).
  3. Include code_challenge and code_challenge_method=S256 when redirecting the user to the authorization endpoint.
  4. When exchanging the authorization code for a token at the token endpoint, include the original code_verifier. The server will verify it matches the previously submitted challenge.

OAuth 2.1 applications must use the S256 challenge method. The plain method is not permitted.

Client Types

OAuth distinguishes between two client types based on their ability to keep credentials confidential (RFC 6749 §2.1):

TypeDescription
ConfidentialServer-side applications that can securely store a client_secret. These clients authenticate at the token endpoint using both client_id and client_secret (via POST body or HTTP Basic Authentication).
PublicBrowser-based (single-page), mobile, or desktop applications that cannot protect a secret. These clients authenticate at the token endpoint using only client_id together with PKCE. No client_secret is required.

Using The Authorization Code Grant

User Authorization

Before making API calls for a user, you must ask that user to authorize your application. First you should redirect the user to DeviantArt's authorization URL along with the required query-string parameters below.

https://www.deviantart.com/oauth2/authorize

Parameters

MethodNameTypeRequiredDescription
GETresponse_typestringrequiredSetting response_type to code is required. Doing so will include the authorization code in the response. Valid values: code.
GETclient_idintegerrequiredYour app's client_id (obtained during app registration).
GETredirect_uristringrequiredYour app's URI which the user should be redirected to after authorizing. This redirect_uri MUST be in your app's redirect URI whitelist; non-whitelisted URIs will be rejected.
GETscopestringoptionalThe scope you wish to access (space separated). Defaults to basic.
GETstatestringoptionalstate will be sent back as part of the redirect_uri query parameters. This should be a unique identifier you create to verify the redirect is coming from your original request. See RFC 6749 §10.12.
GETcode_challengestringrequired (OAuth 2.1)The PKCE code challenge, computed as BASE64URL(SHA256(code_verifier)). Required for OAuth 2.1 applications; optional (but recommended) for legacy OAuth 2.0 applications. See RFC 7636 §4.2.
GETcode_challenge_methodstringrequired (OAuth 2.1)Must be S256. See RFC 7636 §4.3. Valid values: S256.
GETviewstringoptionalForce authentication view if user is logged out. login is the only valid value.

Successful Response

A successful response means that the user will be redirected to your whitelisted URI along with the following GET parameters:

MethodNameTypeDescription
GETcodestringThe code will be returned to you on successful authorization. You can then use this to obtain the access_token.
GETstatestring (optional)If you included the state parameter in your initial redirect request, that value will be returned to you in this field.

Unsuccessful Response

If the authorization request fails for any reason, the user will be redirected back to your whitelisted URI along with the following GET parameters:

MethodNameTypeDescription
GETerrorstringThe error code for the error as defined by the specification. See RFC 6749 §4.1.2.1.
GETerror_descriptionstringThe description of the error.

Please read the error documentation for detailed error handling guidelines.

Example Authorization Redirect

OAuth 2.1 (with PKCE):

GET https://www.deviantart.com/oauth2/authorize?response_type=code&client_id=0&redirect_uri=https://myapp.example/cb&scope=basic&state=mysessionid&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256

Legacy OAuth 2.0 (without PKCE):

GET https://www.deviantart.com/oauth2/authorize?response_type=code&client_id=0&redirect_uri=http://myapp.example/cb&scope=basic&state=mysessionid

Getting A User Access Token

Once you have the code from the authorization step, you can then request an access_token to gain access to the API resources. You do this by sending a POST request to the /token endpoint.

https://www.deviantart.com/oauth2/token

Parameters

MethodNameTypeRequiredDescription
POSTclient_idintegerrequiredYour app's client_id (obtained during app registration). Confidential clients may alternatively provide client_id and client_secret via HTTP Basic Authentication.
POSTclient_secretstringrequired (confidential clients)Your app's client_secret (obtained during app registration). Not required for public clients, which authenticate via PKCE instead.
POSTgrant_typestringrequiredThe value must be authorization_code unless you are refreshing a token (see Refreshing An Access Token).
POSTcodestringrequiredThe code from the authorization step.
POSTredirect_uristringrequiredThe redirect_uri sent with the authorization request to obtain the code. This must exactly match the value sent in that request. Required when grant_type is authorization_code.
POSTcode_verifierstringrequired (OAuth 2.1)The original PKCE code verifier string (43–128 characters). The server computes BASE64URL(SHA256(code_verifier)) and compares it to the code_challenge sent during authorization. Required for OAuth 2.1 applications; required for OAuth 2.0 applications if code_challenge was included in the authorization request. See RFC 7636 §4.5.

Successful Example (Confidential Client)

A successful token request will return a Bearer token in JSON format. See RFC 6750.

Request ===>

curl https://www.deviantart.com/oauth2/token \
  -d grant_type=authorization_code \
  -d client_id=0 \
  -d client_secret=mysecret \
  -d redirect_uri=https://myapp.example/cb \
  -d code=1234 \
  -d code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

Response <===

{
  "expires_in": 3600,
  "status": "success",
  "access_token": "Alph4num3r1ct0k3nv4lu3",
  "token_type": "Bearer",
  "refresh_token": "3ul4vn3k0tc1r3mun4hplA",
  "scope": "basic"
}

Successful Example (Public Client)

Public clients omit client_secret and rely on PKCE for proof of possession.

Request ===>

curl https://www.deviantart.com/oauth2/token \
  -d grant_type=authorization_code \
  -d client_id=0 \
  -d redirect_uri=https://myapp.example/cb \
  -d code=1234 \
  -d code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

Response <===

{
  "expires_in": 3600,
  "status": "success",
  "access_token": "Alph4num3r1ct0k3nv4lu3",
  "token_type": "Bearer",
  "refresh_token": "3ul4vn3k0tc1r3mun4hplA",
  "scope": "basic"
}

Unsuccessful Example

Request ===>

curl https://www.deviantart.com/oauth2/token \
  -d grant_type=authorization_code \
  -d client_id=0 \
  -d client_secret=mysecret \
  -d redirect_uri=https://myapp.example/cb \
  -d code=0

Response <===

{
  "error": "invalid_request",
  "error_description": "Incorrect authorization code."
}

Please read the error documentation for detailed error handling guidelines.

Refreshing An Access Token

All access_tokens expire after one hour. After expiration you either need to re-authorize the app or refresh your access token using the refresh_token from the /token request.

The refresh_token will expire after 3 months. After that time you must re-authorize the app.

Parameters

MethodNameTypeRequiredDescription
POSTclient_idintegerrequiredYour app's client_id (obtained during app registration). Confidential clients may alternatively provide credentials via HTTP Basic Authentication.
POSTclient_secretstringrequired (confidential clients)Your app's client_secret (obtained during app registration). Not required for public clients.
POSTgrant_typestringrequiredThe value must be refresh_token.
POSTrefresh_tokenstringrequiredThe refresh_token of the Bearer token.

Example Token Refresh

Request ===>

curl https://www.deviantart.com/oauth2/token \
  -d grant_type=refresh_token \
  -d client_id=0 \
  -d client_secret=mysecret \
  -d refresh_token="3ul4vn3k0tc1r3mun4hplA"

Response <===

{
  "expires_in": 3600,
  "status": "success",
  "access_token": "Alph4num3r1ct0k3nv4lu3",
  "token_type": "Bearer",
  "refresh_token": "3ul4vn3k0tc1r3mun4hplA",
  "scope": "basic"
}

Using The Client Credentials Grant

Getting A Client Access Token

To obtain a client access token, you simply request a token using your client's client_id and client_secret.

Parameters

MethodNameTypeRequiredDescription
POST, GETclient_idintegerrequiredYour app's client_id (obtained during app registration). client_id and client_secret can be provided via HTTP Basic Authentication. See RFC 6750 §2.1.
POST, GETclient_secretstringrequiredYour app's client_secret (obtained during app registration). client_id and client_secret can be provided via HTTP Basic Authentication. See RFC 6750 §2.1.
POST, GETgrant_typestringrequiredThe value must be client_credentials.

Successful Example

A successful token request will return a Bearer token in JSON format. See RFC 6750.

Request ===>

curl https://www.deviantart.com/oauth2/token \
  -d grant_type=client_credentials \
  -d client_id=0 \
  -d client_secret=mysecret

Response <===

{
  "expires_in": 3600,
  "status": "success",
  "access_token": "Alph4num3r1ct0k3nv4lu3",
  "token_type": "Bearer"
}

Unsuccessful Example

Request ===>

curl https://www.deviantart.com/oauth2/token \
  -d grant_type=client_credentials \
  -d client_id=0 \
  -d client_secret=mybadsecret

Response <===

{
  "error": "invalid_client",
  "error_description": "Client authentication failed."
}

Please read the error documentation for detailed error handling guidelines.

Using The Implicit Grant

Deprecated. The Implicit grant (response_type=token) is not available to new applications. It is retained only for legacy OAuth 2.0 clients that were registered with implicit access before the introduction of OAuth 2.1. New applications should use the Authorization Code grant with PKCE, which is secure for both public and confidential clients.

If you have an existing application that uses the Implicit grant, you can upgrade it to OAuth 2.1 from the Applications page. The OAuth 2.1 specification omits the Implicit grant entirely due to its known security vulnerabilities.

Getting Authorization And Access Token (Legacy Only)

To obtain an access_token using the implicit grant you redirect the user to the authorization URL and the access_token will be returned to your client in the fragment of the redirect_uri you provided.

Note that to use the implicit grant you must configure your client's grant_type in the client settings. Implicit clients also require HTTPS redirect URIs and whitelisted URIs must exactly match.

https://www.deviantart.com/oauth2/authorize

Parameters

MethodNameTypeRequiredDescription
GETresponse_typestringrequiredSetting response_type to token is required. Doing so will include the access_token in the response. Valid values: token.
GETclient_idintegerrequiredYour app's client_id (obtained during app registration).
GETredirect_uristringrequiredYour app's URI which the user should be redirected to after authorizing. This redirect_uri MUST be in your app's redirect URI whitelist; non-whitelisted URIs will be rejected.
GETstatestringrequiredstate will be sent back as part of the redirect_uri query parameters. This should be a unique identifier you create to verify the redirect is coming from your original request. See RFC 6749 §10.12.
GETscopestringoptionalThe scope you wish to access (space separated). Defaults to basic.

Successful Example

A successful authorization will redirect the user back to the client with the access_token in the fragment of the URL.

Request ===>

GET https://www.deviantart.com/oauth2/authorize?response_type=token&client_id=0&redirect_uri=https://myapp.example/cb&scope=basic&state=mysessionid

Response <===

GET https://myapp.example/cb#access_token=Alph4num3r1ct0k3nv4lu3&token_type=bearer&expires_in=3600&scope=basic&state=mysessionid

Unsuccessful Example

Request ===>

GET https://www.deviantart.com/oauth2/authorize?response_type=token&client_id=-1&redirect_uri=https://myapp.example/cb&scope=basic&state=mysessionid

Response <===

GET https://myapp.example/cb?error=invalid_request&error_description=Invalid+client.&state=mysessionid

Placebo Call

The first and most basic authenticated API call. It checks that a given access_token is still valid. The endpoint is:

https://www.deviantart.com/api/v1/oauth2/placebo

Example

Request ===>

curl https://www.deviantart.com/api/v1/oauth2/placebo -d access_token=Alph4num3r1ct0k3nv4lu3

Response <===

{
  "status": "success"
}

Notes

This call is most useful for checking that an access_token is still valid before making another API call that might take a long time (like a file upload). This way, if a token has expired, your users won't have to wait until the upload (or any other long-running API call) returns an error before your app notices and makes a /token call to refresh the expired token.

Revoking Access / Logging Out

Sometimes the user may want to log out or revoke access to the application. In these situations the application may choose to revoke access by itself. Note that if the application provides a means to log out, you should implement this call.

To manually revoke access you can provide either an access_token or refresh_token to identify the user and revoke your application's access to their account. This will revoke all access tokens, refresh tokens and authorizations, meaning applications would need to restart the authorization process to obtain account access again.

The default revoke removes all tokens for the user. If you want to just revoke a single device/session you can pass revoke_refresh_only=true. This will just revoke the refresh_token that is sent in with the revoke request.

POST https://www.deviantart.com/oauth2/revoke

Example

Request ===>

curl https://www.deviantart.com/oauth2/revoke -d token=Alph4num3r1ct0k3nv4lu3

Response <===

{
  "success": true
}